The Automatic Certificate Management Environment (ACME) modules obtain, install, renew, and revoke Transport Layer Security (TLS) certificates. They implement the client side of RFC 8555 and work with Let's Encrypt or another compatible ACME service. The modules are shared by the Barracuda App Server (BAS), Mako Server, and Xedge.
A certificate lets an HTTPS client verify the identity of your server. ACME automates obtaining and renewing that certificate. Before choosing a configuration, decide how the certificate authority (CA) will verify that your server is authorized to use its name:
| Validation method | Use it when | Connection required |
|---|---|---|
| HTTP-01 | The ACME service can connect directly to the server by its public domain name. | Inbound HTTP on public TCP port 80, plus outbound HTTPS to the ACME service. |
| Automatic DNS-01 | The server is on a private network and a SharkTrust portal manages its DNS record. | Outbound HTTPS to both the portal and the ACME service. |
| SharkCA private enrollment | You manage the trust root for private .local names or local IPv4 addresses. | The SharkCA portal over outbound HTTPS. |
| Manual DNS-01 | An operator can create the required DNS TXT record. | The public DNS record. The server still needs outbound HTTPS access to the ACME service. |
Automatic DNS-01 is useful for memory-constrained embedded systems because it does not require a public inbound connection. It works with Xedge or with an application built directly from the Barracuda App Server libraries.
HTTP-01 proves control by serving a temporary file on your server. DNS-01 proves control by publishing a temporary text (TXT) record in the Domain Name System (DNS). SharkCA instead uses authenticated device enrollment and a private trust root.
Choose your entry point. On Mako Server, start with the mako.conf settings. On Xedge, use the certificate-settings interface. Those hosts create the runtime for you. To manage certificates from Lua, start with the examples below and acme/runtime. The DNS adapter, certificate manager, and protocol engine are covered later for custom integrations.
Start with staging for public certificates. The examples select the Let's Encrypt staging service with
production=false. Staging certificates are not trusted by browsers, but staging lets you test without consuming production rate limits. Change the setting totrueonly after the complete flow works. SharkCA uses its own private CA and has no staging selector.
The four examples use the same runtime on Mako Server and Xedge. The runtime selects the host's writable I/O automatically and installs certificates in the standard ba.slcon and ba.slcon6 HTTPS listeners. An application that embeds the BAS library directly must supply an io option and the install callback described under Runtime.create(). You can also supply these options on Mako or Xedge when using different storage or HTTPS listeners.
Before running an example, make sure networking, the system clock, a trusted HTTPS client, and private writable storage are ready. Replace the sample domain and email with your own values. See runtime and build requirements for custom BAS hosts.
The notify(code, msg) function receives a numeric lifecycle code and, for two events, an optional message string. The startup callback reports whether certificate management started successfully. Do not log private keys, SharkTrust credentials, zone secrets, proof values, or authorization headers.
Use the same configuration table on Mako, Xedge, or a custom BAS host. Omitting challenge selects HTTP-01. The certificate authority must reach the device on public TCP port 80.
local runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"device.example.com"},
production = false
},
-- These messages contain lifecycle codes and optional non-secret details.
notify = function(code, msg) trace("ACME event ", code, msg or "") end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem)
if not result then
trace("ACME startup failed: ", problem.message or problem.code)
end
end)
A SharkTrust portal publishes and removes the TXT record. When credentials are omitted, the shared DNS module uses the host's compiled etokengen or tokengen identity.
local runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"controller"},
production = false,
namePolicy = "exact",
challenge = {type="dns-01", dns="local"}
},
notify = function(code, msg) trace("ACME event ", code, msg or "") end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem)
-- The runtime retries startup failures while it remains open.
if not result then
trace("ACME startup failed: ", problem.message or problem.code)
end
end)
For an explicit identity, set challenge.portalUrl, challenge.zoneKey, and challenge.proof(message) together. The client does not accept a secret option. A host callback calculates the proof from provisioned credentials. Keep credentials outside the application ZIP and source repository. The configuration fields are described below.
The runtime uses the first domain as the requested device name, then manages the name assigned by the portal. It stores registration with the ACME state unless the host supplies a custom store. Local IPv4 discovery is automatic; forward later address changes with runtime:setIpAddress(newIpAddress, callback).
If the configured portal or zone identity differs from the saved registration, startup automatically enrolls with the configured identity and replaces the local registration. It does not remove the device from the previous portal. Switching back therefore requires a new registration; namePolicy="exact" can report name_unavailable if the old device still owns that name.
Manual mode pauses issuance until an operator publishes the TXT record. It uses the same constructor; no separate adapter setup is required.
local runtime, err
runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"device.example.com"},
production = false,
challenge = {type="dns-01", mode="manual"}
},
notify = function(code)
if code == 32 then
local record = runtime.challenge:status()
print("Create TXT record:", record.recordName, record.recordData)
end
end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem)
-- Manual issuance stays pending until the operator confirms the TXT record.
if not result then
trace("ACME startup failed: ", problem.message or problem.code)
end
end)
After a public DNS lookup returns the exact TXT value, continue the pending operation:
local challenge = runtime.challenge
if challenge:status().phase == "publish" then
challenge:continue(function(ok, problem)
-- This confirms publication; the startup callback reports final completion.
if not ok then trace("DNS confirmation failed: ", problem.message or problem.code) end
end)
end
The operator removes the TXT record after validation. Use runtime.challenge:cancel() to cancel the pending publication step.
Use SharkTrust Private CA (SharkCA) for certificates covering private device names such as controller.local, local IPv4 addresses, or both. Devices enroll with your portal and obtain certificates over outbound HTTPS. They do not need a public DNS record or an inbound HTTP challenge.
Before running this example:
acme/http.setCertStore() before creating the runtime.
local runtime, err = require"acme/runtime".create {
config = {
domains = {"controller"}, -- Request a device name in the portal's zone.
sharkca = {} -- Use the compiled identity for this SharkCA zone.
},
notify = function(code, msg) trace("ACME event ", code, msg or "") end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem)
-- Startup enrolls the device and installs its certificate.
if not result then
trace("SharkCA startup failed: ", problem.message or problem.code)
end
end)
Use domains={} for an IP-only certificate. The zone must permit IP issuance and the device's local address. SharkCA needs no email address, terms acceptance, or production/staging selector. Its certificates use Elliptic Curve Cryptography (ECC).
To enter credentials without rebuilding the host, use Mako's acme.sharkca settings or the Xedge certificate-settings interface. For an explicit identity in Lua, see SharkCA configuration. Choose one owner for the host's HTTPS certificates; do not also start this runtime when Mako or Xedge already manages them.
SharkCA issues certificates but does not provide DNS services. Named devices normally use multicast DNS (mDNS) on the local network. Mako's configuration and Xedge's settings provide name advertisement; a runtime created directly from Lua needs the host's name-resolution integration. Portal administration and trust distribution are covered in the SharkCA user manual.
Call runtime:close(callback) during application unload. It cancels owned work, removes an active challenge when possible, closes network clients, and prevents new operations. On a device that starts before its clock is valid, wait for the clock synchronization event before calling start(). Certificate validation and HTTPS server trust checks require a correct clock.
Mako users can configure the same runtime in mako.conf. Xedge users normally configure it in the Xedge certificate user interface.
In mako.conf, acme.challenge.secret is an optional 64-character hexadecimal string that can replace proof when supplied with portalUrl and zoneKey. Mako creates the proof callback before calling the shared runtime; an explicit proof callback takes precedence. Direct callers of Runtime.create() and Dns.createClient() must still supply a proof callback for an explicit identity.
| Public module | Use it for |
|---|---|
acme/runtime | The normal entry point for startup, certificate management, and shutdown. createManager() exposes certificate management separately for custom hosts. |
acme/dns | Automatic and manual DNS-01. createClient() exposes direct SharkTrust enrollment, DNS commands, address updates, and reverse connections. |
acme/engine | ACME protocol operations, renewal information, software and Trusted Platform Module (TPM) keys, and HTTP-01 challenges. |
acme/http | Shared HTTPS trust settings, including a private CA store for a SharkCA portal. |
The certificate manager is created through acme/runtime; the SharkTrust client is created through acme/dns. You do not need separate manager or SharkTrust modules. The package also contains acme/_util and acme/_server, which are private host implementation details.
The modules require the auxiliary Lua bindings, an HTTPS client with a trusted CA store, a valid system clock, and private writable storage. The I/O interface is the BAS object used to read and write that storage. A BAS build that creates software keys and certificate signing requests (CSRs) must enable these SharkSSL options:
#define SHARKSSL_ENABLE_ASN1_KEY_CREATION 1 #define SHARKSSL_ENABLE_RSAKEY_CREATE 1 #define SHARKSSL_ENABLE_ECCKEY_CREATE 1 #define SHARKSSL_ENABLE_CSR_CREATION 1
Add missing definitions to the platform's inc/arch/[platform]/TargConfig.h or compiler options. RSA certificate keys also require RSA support in the SharkSSL build. Mako Server and Xedge packages that include the ACME plugin provide the required integration.
A Trusted Platform Module (TPM) can hold private ECC keys and perform signing without exposing those keys to Lua. The stack uses the host's TPM interface when available; otherwise it creates software keys. See TPM interface for a custom host.
Asynchronous methods use callback(result, err). On success, result contains a value and err is nil. On failure, result is nil and err is a structured error table. A storage load() callback may return nil, nil to mean that no saved state exists.
{
code = "bad_nonce",
message = "The ACME server rejected the replay nonce",
temporary = true,
status = 400,
type = "urn:ietf:params:acme:error:badNonce",
detail = "...",
retryAfter = 15,
operation = "newOrder",
url = "https://acme.example/directory/new-order"
}
temporary is true. Runtime startup still retries once per hour while open.phase is request, write, or read.A method may return nil, err before it starts, usually because an argument is invalid or the object is closed. After an asynchronous operation starts, its callback is invoked once. Transport errors can include cause and phase, where the phase is request, write, or read.
Lua callers must supply the documented argument types, supported option values, and callbacks. Internal calls do not repeat every argument or interface check. Incorrect Lua API use is a programming error; do not depend on an invalid_* result for every malformed argument. Network responses, persisted credentials, service identity, terms acceptance, and operation lifecycle still receive the required checks.
The optional notify(code, msg) callback reports lifecycle events. code is an integer. msg is a string for codes 3 and 13, and nil for the other codes. Use these events to update a user interface or write an application log. The callback returns no value, must return promptly, and must not yield. Callback errors are caught and traced.
| Code | Meaning and optional message |
|---|---|
1 | Certificate management starting. |
2 | Certificate management ready. |
3 | Startup attempt failed. msg is the error code string, including on automatic retries. A supplied start completion callback also receives the structured error for its attempt. Mako and Xedge log the code as ACME event 3: <error code>. |
4 | Startup retry scheduled. |
10 | Device enrollment starting. |
11 | Device enrolled. |
12 | Saved registration being restored. |
13 | Registration confirmed after enrollment or startup restoration. msg is the full assigned domain name, or an approved identifier for an IP-only SharkCA registration. |
20 | Reverse connection enabled. This does not mean it is connected. |
21 | Reverse connection disabled. |
30 | Automatic DNS TXT record published; propagation wait starting. |
31 | Automatic DNS TXT record successfully removed. |
32 | Manual DNS TXT publication required. Read the manual adapter status for the record name and value. |
40 | Certificate issued and saved; installation follows. |
41 | Certificate renewed and saved; installation follows. |
42 | Certificate revocation accepted and local record removed. |
50 | ACME service profile committed. |
Ignore unknown future codes. Only codes 3 and 13 carry the message described above. Certificate events do not identify a domain; refresh runtime:status() to find the current state. Use completion callbacks for operation results and detailed errors. For code 32, read challenge:status() for the TXT record, then call continue() or cancel() through the host interface.
local service = {
production = false,
productionUrl = "https://acme.example/production/directory",
stagingUrl = "https://acme.example/staging/directory",
http = {
proxy = "proxy.example.com",
proxyport = 8080,
shark = trustedSharkSslClient
}
}
The service table selects the ACME directory:
The selected directory URL identifies an ACME account and certificate profile. Staging and production state are kept separate. Changing the active directory through the manager or runtime uses a transactional service switch, described under manager:switchService().
acme/runtimeacme/runtime is the recommended high-level API. It creates an engine and manager, selects the HTTP or DNS challenge adapter, restores saved state, starts renewal, and closes the owned objects in the correct order.
Creates the high-level certificate runtime. Use this constructor for normal application integrations. Mako and Xedge configuration users do not call it because those hosts create the runtime automatically.
local Runtime = require"acme/runtime" local runtime, err = Runtime.create(options)
Parameters
home; standalone Xedge defaults to disk. Xedge's built-in integration passes its selected I/O explicitly.install(records, callback) activates the complete certificate set. Mako Server and Xedge provide a default for their standard HTTPS listeners. Supply this function when embedding BAS directly or when any host uses custom listeners.acme table.load(callback) and save(state, callback) functions. Automatic DNS uses sharktrust.json below the runtime's storage directory when this option is omitted. See SharkTrust state storage.type, present, and cleanup. Used when config.challenge does not select a built-in DNS mode.io. The default is acme.notify(code, msg) receives an integer lifecycle code and an optional string message.renewAllowed(domain, expiresAt) is called before a scheduled renewal. domain is a string and expiresAt is the certificate expiration as a numeric Unix timestamp in seconds, or nil if unavailable. No certificate or private key is passed. Return false to defer the renewal for one hour. Any other return value permits it. Forced renewal ignores this callback. The callback must not throw; its Lua errors propagate and interrupt scheduled renewal processing.Return values
Throws
The listed validation failures return errors. Incorrect field types or missing required nested fields can raise Lua errors. Errors from supplied components and native setup can propagate. Most configuration and key validation occurs later during startup.
Pass this table as options.config on every host, or as acme in mako.conf. Direct Lua callers supply the documented types. Host UI input validation stays at the UI boundary.
The optional challenge table selects type="dns-01" (string). Its optional mode is automatic (default) or manual (string). Automatic mode accepts portalUrl (HTTPS string), zoneKey (64-character hex string), and proof(message) (required function returning 32 binary bytes for a string message). See the proof callback contract. Omit the identity fields to use the compiled identity. Optional dns is local (default), wan, or both (string); reverse is a boolean defaulting to false; propagationDelay is seconds (number, default 30, zero allowed). Manual mode needs only type and mode.
Set config.sharkca to a table to select the private enrollment profile. An empty table uses the host's compiled zone identity. For an explicit identity, supply the following fields together:
/sharktrust.lsp endpoint. With a compiled identity, this field is optional and defaults to that identity's portal address; a supplied URL overrides the address.proof to use the compiled identity.config.domains is a required array containing zero or one device-name string. Use {"controller"} for a name or {} for IP-only issuance. The portal's zone policy selects the approved certificate names and addresses. The profile supports ECC keys only and does not accept config.challenge. Email, terms acceptance, and public production/staging fields are unused. There is no fallback to a public ACME service.
The secret and caFile fields belong to Mako's configuration loader, which derives the proof callback and loads a PEM trust file. Direct Runtime.create() callers supply the proof callback themselves and configure portal HTTPS trust when the existing trust store does not trust the portal's issuer.
The manager calls this function whenever its active certificate set changes. Replace a non-empty set atomically if possible. An empty records array means the manager has no certificates to supply; the host determines how to handle its existing HTTPS listeners. Mako and Xedge applications normally omit this callback because their standard HTTPS listeners use the built-in installer.
The built-in installer intentionally leaves the currently installed certificates in place when records is empty. It does not switch to the self-signed default. Thus removing or revoking the last managed certificate does not immediately stop the listeners from presenting it. The installed set remains until another non-empty set replaces it or the host restarts. A custom installer must define its own empty-set behavior.
local function installCertificates(records, callback) -- Convert each record for the platform and replace the active TLS set. -- Call callback only after every record is active, or after the update fails. callback(true, nil) end
Parameters
Return values
The installer's direct return values are ignored. Completion must use callback, synchronously or asynchronously. The manager remains busy until completion; it does not interpret a direct nil, err return as failure.
Throws
Installer exceptions and callback-reported failures become certificate_install_failed error tables. For a table error, the manager keeps its message; other error fields are not forwarded. Duplicate completion calls are ignored. An exception after completion does not replace the completed result.
The client discovers the local IPv4 address used for the portal connection and sends it during enrollment. The application supplies only the naming, DNS publication, and descriptive fields below.
The registration table supplies SharkTrust enrollment data:
{
name = "controller",
namePolicy = "exact",
dns = "local",
info = "BAS controller"
}
exact rejects an unavailable requested name. increment permits a numbered alternative. An explicit name defaults to exact.local, wan, or both. The default is local. See Selecting the Published Address.enrollment_credential_mismatch. The normal DNS adapter generates this value itself. Without a supplied credential, a lost write/read response remains enrollment_state_unknown with retryable=false.Starts certificate management. Call this once after storage, networking, DNS, and the system clock are ready. It restores saved certificates and SharkTrust registration, enrolls when needed, obtains missing certificates, and starts renewal.
For SharkCA, startup saves the account key before enrollment, checks the portal's sharkca-v1 capability and account association, and restores saved registration before requesting a certificate. The runtime manages one stable $device certificate record.
Parameters
result is a table whose boolean started member is true when this call started the runtime or false when it was already running. A new or changed service profile adds table switch with boolean changed, boolean reused, and number rebuilt. A non-fatal registration check can add table warning containing the structured error. On failure, result is nil and err is the error table.The method is idempotent. Every reported startup failure is returned to the callback and retried in the background while the runtime remains open. Temporary, retryable errors use a delay starting at 30 seconds and doubling to five minutes. Other errors, including name_unavailable, retry once per hour. There is no attempt limit. Closing the runtime cancels retry. Incorrect configuration, unavailable storage or an occupied name may still need operator correction.
Return values
Throws
Reported storage, enrollment, issuance and installation failures use the callback. Completion callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Checks the current device registration with SharkTrust and refreshes the portal with the automatically discovered local IPv4 address. Use it for diagnostics or a registration-status user interface. Normal startup performs this work automatically.
Parameters
result contains boolean registered and may contain string deviceId and string name when registered. With the built-in DNS client, string sockname is the local IPv4 address of the connection to the portal. Without a SharkTrust configuration, err.code is sharktrust_not_configured.Return values
For SharkCA, this method resumes the saved registration and applies the portal's approved certificate identifiers. When they change, success is reported only after the replacement certificate is installed. Failure leaves the previous certificate installed. Address-change behavior and overlapping operations are described under setIpAddress().
Throws
Reported storage and portal failures use the callback. Callback errors are caught and traced. Errors raised by supplied components can propagate.
Checks whether a requested SharkTrust device name appears available. Use it only as an advisory user-interface check. Enrollment performs the authoritative check and can still report a conflict.
Parameters
result is {available=boolean, name=string}, where name is the normalized full name.Return values
Throws
Reported portal failures use the callback. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Updates the local IPv4 address stored by the portal. SharkTrust refreshes the DNS A record; SharkCA replaces the certificate when the approved identifiers change. Use it after startup when DHCP or another network event reports that the device address changed. Startup discovery and the first update are automatic.
Parameters
192.168.1.20.result is the portal acknowledgement table. Without a SharkTrust configuration, err.code is sharktrust_not_configured.Return values
For SharkCA, call this method after startup. The runtime saves accepted registration changes, keeps the $device record's private key, and installs a replacement certificate when the approved identifiers change. Its callback receives the portal registration result only after installation succeeds. If replacement fails, the previous certificate stays installed.
An overlapping portal update can report operation_in_progress; retry it after the current callback. If the identifiers change during issuance, the superseded request can report identifiers_changed while the runtime proceeds with the latest identifiers. Calling before SharkCA startup reports runtime_not_started.
Throws
Reported storage and portal failures use the callback. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Changes the SharkTrust reverse-connection state immediately. Use it when an application lets an operator enable or disable portal-assisted remote access after startup.
Parameters
Return values
Throws
Reported configuration and proof failures return nil, err. Native reverse-connection option errors and exceptions from supplied components can propagate.
Moves certificate management to another ACME directory. Use it to change between staging and production or to select another compatible provider. Existing certificates stay installed until the new profile is ready. SharkTrust registration does not change.
Parameters
boolean production.result contains boolean changed, boolean reused, and, when rebuilding, number rebuilt.Return values
SharkCA does not switch directories through this method; its callback reports sharkca_reconfigure_required. Close the runtime and create it again with the new portal configuration.
Throws
Uses the exception and error-reporting behavior documented for manager:switchService().
Immediately requests a replacement certificate even when the current certificate is not near expiration. Use it for an operator-requested renewal or after a certificate-related policy change. Scheduled renewal needs no application call.
Parameters
$device record.result is the new certificate record. The current certificate remains installed until replacement succeeds.Return values
Throws
Uses the exception and error-reporting behavior documented for manager:renew().
Returns an operational snapshot for status pages, diagnostics, and health checks. The built-in components do not include private keys or device credentials.
Parameters
None. Additional arguments are ignored.
Return values
{
loaded = true,
started = true,
closed = false,
starting = false,
retryPending = false,
operation = nil,
directoryUrl = "https://acme.example/directory",
domains = {},
jobs = {},
lastError = nil,
retryAt = nil,
registration = challengeStatusOrNil,
reverse = {enabled=true, connected=true, status=202, connections=3}
}
close() prevents further work.expiresAt, renewAt, and optional ARI fields.{enabled=boolean, connected=boolean, status=number, connections=number}.Throws
Exceptions raised by an underlying status method, including a custom challenge adapter's status() method, propagate. Lua allocation errors can also propagate.
Stops certificate management and releases owned resources. Call it during application unload. It closes the manager and challenge adapter and cancels owned work.
Parameters
Repeated close calls succeed immediately, without waiting for an earlier close to finish or retrying cleanup. Their callbacks receive true, nil.
Return values
If a custom certificate installer or automatic DNS registration operation is still pending, returns nil, err (string) with err equal to "busy". Registration operations include loading or saving state, enrollment and identity switching. Shutdown has not begun: both components remain open, timers are unchanged, and the supplied close callback is not called. Retry close after the operation finishes. The built-in installer completes synchronously.
Throws
Reported cleanup failures go to the callback as nil, err. Errors raised by the completion callback are caught and traced. A custom challenge adapter must follow its callback contract; an exception from its close() method is not converted to a cleanup error result.
runtime.challenge contains the selected challenge adapter. Most applications do not use it directly. A manual DNS user interface uses it to call status(), continue(), or cancel().
acme/dnsacme/dns creates DNS-01 challenge adapters. Use createSharkTrust() for automatic DNS updates or createManual() for an operator-assisted flow.
Creates a DNS-01 challenge adapter that uses SharkTrust to publish TXT records and persists the device registration. Runtime.create() calls this constructor automatically when config.challenge selects automatic DNS-01. Call it directly only when assembling an engine and manager without the runtime.
local Dns = require"acme/dns"
local challenge, err = Dns.createSharkTrust {
client = sharkTrustClient,
store = {
load = function(callback) callback(savedState, nil) end,
save = function(state, callback) callback(true, nil) end
},
propagationDelay = 30,
notify = function(code) end
}
Parameters
function load(callback) and function save(state, callback), described below.Return values
Throws
Incorrect options or a missing/incompatible client can throw. Store callbacks are used later; exceptions from store.load and store.save are converted to storage_read_failed and storage_write_failed errors.
When used with acme/runtime, this store also retains ACME account keys or TPM key descriptors in an accounts table indexed by service ID. Save and restore the entire state table. Before enrollment, it may contain account state without a device credential. Xedge uses encrypted xcfg.bin; the default runtime store uses acme/sharktrust.json. Protect this store as private key material when software keys are used.
Both SharkTrustX and SharkCA can restore a deleted service profile from this retained account identity and obtain another certificate without changing the registered device or name. After upgrading an existing installation, let it start successfully with its original service file present before deleting that file. An account identity already lost before the upgrade cannot be restored by this feature. For normal forced renewal, use runtime:renew() instead of deleting files.
The adapter calls store.load and store.save as plain functions, without an implicit self argument. Both functions must call their callback exactly once:
Parameters
Return values
Ignored. Report completion exactly once through callback.
Throws
Exceptions are caught and reported as storage_read_failed. Callback-reported errors use the same code, with the supplied message. Errors raised after completion do not replace the result.
Parameters
Return values
Ignored. Report completion exactly once through callback. The adapter serializes saves and retains failed state for a later resume() retry.
Throws
Exceptions and callback-reported errors become storage_write_failed errors with the supplied message. Other table error fields are not forwarded. Duplicate completions and exceptions after completion do not replace the result.
callback(state, nil) -- load: state was found callback(nil, nil) -- load: no state exists callback(nil, err) -- load: read failed callback(true, nil) -- save: durable commit completed callback(nil, err) -- save: commit failed
save() must not report success until the data is durably committed. A filesystem implementation can write a temporary file and rename it. The adapter serializes save operations.
{
version = 2,
portalUrl = "https://portal.example.com/sharktrust.lsp",
zoneIdentity = "<opaque-non-secret-fingerprint>",
deviceId = "0123456789abcdef0123",
name = "controller.example-zone.com",
credential = "<64-lowercase-hexadecimal-characters>",
updatedAt = 1788105600
}
The credential is secret. Protect it with the strongest storage available on the target. Do not place this state in an application ZIP, source repository, public resource, log, or diagnostic download. The adapter rejects malformed state and state belonging to another portal or zone identity.
Direct returns acknowledge submission; callbacks report completion and may run before the method returns. Use the runtime methods for ordinary application code.
Registers the device and saves its assigned identity.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Performs an advisory name-availability check; enrollment makes the final decision.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Loads and validates saved registration state. Concurrent loads share the same pending read.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Confirms saved registration with the portal and persists a changed assigned name. First retries a pending failed state save.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Checks registration and updates the portal with the automatically discovered local IPv4 address.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Updates the registered local IPv4 address after a network-address change.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Reads the public IPv4 address observed by the portal.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Replaces the portal client. Changing the portal or zone identity requires enrollment and persistence before replacing the active registration.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Publishes the TXT record and waits for the propagation delay. Called by the ACME engine.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Reads a non-secret status snapshot.
Parameters
None.
Return values
Throws
Does not throw for valid adapter state.
See the separate cleanup() and close() contracts below.
Clears the active challenge and cancels its propagation timer. A pending present() callback receives nil and an error table with code challenge_cancelled. When registration state exists, cleanup requests removal of the TXT record.
Parameters
Return values
Throws
Removal failures are reported through the callback. Errors from the pending present() callback or completion callback are caught and traced. Incorrect use of a supplied client or timer may throw.
Cancels the pending challenge and its propagation timer. If a registration and active challenge exist, it attempts to remove the TXT record before closing the client. Client cleanup proceeds even when record removal fails.
Parameters
Return values
After shutdown has started, repeated calls return no values and invoke the supplied callback immediately with true, nil. They neither wait for the first call nor retry failed cleanup.
Throws
Reported removal and close failures are delivered to the callback. Completion callback errors are caught and traced. A supplied client must implement the documented methods and callback contracts; errors from incorrect client usage are not converted to cleanup error results.
switchIdentity() is required when the portal URL, zone key, zone secret, or generated proof identity changes. Without explicit re-enrollment permission, it returns sharktrust_identity_change_requires_reenrollment. An ACME production or staging change does not change SharkTrust identity.
challenge:switchIdentity(
{client = newClient},
{
reenroll = true,
enrollment = {
name = "controller",
namePolicy = "exact",
dns = "local",
info = "BAS controller"
}
},
function(result, err)
-- result.changed is true when the identity was replaced.
-- result.state contains the newly saved registration state.
end)
Creates an operator-assisted DNS-01 adapter. Use it when the application cannot update DNS automatically and can show the TXT record to an operator.
local challenge = Dns.createManual {
-- Code 32 tells the host to read challenge:status() and display the TXT record.
notify = function(code) end
}
Parameters
status().Return values
Throws
Throws if options cannot be used as an options table. Notification callback errors are caught and traced when a notification is delivered.
The manual adapter implements present(context, callback) and cleanup(context, callback) for the engine. Application code uses these methods:
Returns the information needed to display the pending DNS record.
Parameters
None.
Return values
Throws
Does not deliberately throw for a valid adapter and challenge context.
Continues validation after the operator confirms that the TXT record is publicly visible.
Parameters
Return values
Throws
No pending action is reported as an error result. Errors raised by the engine or completion callback are caught and traced.
Cancels the pending operator action and returns the adapter to idle. The engine's pending present() callback receives nil and an error table with code challenge_cancelled.
The old action is cleared before its callback runs, so a callback can cancel again or start a new action without notifying the old action twice.
Parameters
Return values
Throws
Errors raised by the engine or completion callback are caught and traced.
Closes the adapter and cancels any pending action. Later engine present() calls fail with adapter_closed. Repeated close calls succeed.
Parameters
Return values
Throws
Errors raised by cancellation or completion callbacks are caught and traced.
The module does not send email. A host may display the manual adapter status in a user interface or forward it through its own email service.
The manager in acme/runtime owns persistent ACME state, certificate installation, renewal scheduling, revocation, and service profiles. Most applications should use acme/runtime. Use the manager directly only when the application must assemble these responsibilities separately from SharkTrust or other runtime services.
The manager is a lower-level API and therefore always requires a certificate installer. In the example, installCertificates is the host function defined by the certificate installation callback contract. Mako and Xedge automatic installation applies to Runtime.create(), not to a manager constructed directly.
local Runtime = require"acme/runtime"
local manager, err = Runtime.createManager {
io = writableIo,
engine = engine,
install = installCertificates, -- host callback described above
notify = function(code) end,
renewAllowed = function(domain, expiresAt) return true end,
path = "acme"
}
Parameters
domain is a string and expiresAt is the certificate expiration as a numeric Unix timestamp in seconds, or nil if unavailable. No certificate or private key is passed. Return false to defer renewal for one hour. Any other result permits it. Forced renewal ignores this callback. The callback must not throw; its Lua errors propagate and interrupt scheduled renewal processing.io. The default is acme.Return values
Throws
A missing or incorrectly typed options argument can throw. Incorrect path types can throw during construction; I/O, engine and callback interfaces must satisfy their documented contracts and are used later.
Sets the desired domains, ACME service, challenge adapter, and certificate-key policy. Call it before start() when using the manager directly. Calling it does not contact the ACME service.
local ok, err = manager:configure {
email = "operator@example.com",
domains = {"device.example.com"},
acceptTerms = true,
service = {production = false},
challenge = challengeAdapter,
key = {type = "ecc", curve = "SECP384R1"},
cleanup = true,
timeout = 600,
dnsResolveTimeout = 30,
fallbackRenewBefore = 22 * 24 * 60 * 60
}
boolean production.string type, function present(context, callback), and function cleanup(context, callback). Omit it for the built-in HTTP-01 adapter.string type is ecc (default) or rsa; string curve defaults to SECP384R1 for ECC; number bits defaults to 2048 for RSA.Runtime.create() passes its configured value.Parameters
Return values
Throws
Configuration validation failures use the error results above. Supply the documented types and ordinary configuration tables; values that cannot be copied or used by the configured components may raise Lua errors. Errors from later operations are reported by those operations.
ECC certificate keys use the platform TPM when its key interface is available; otherwise they are created as software keys. RSA keys are always software keys.
Loads saved state and installs the active certificate set without contacting an ACME service. Repeated calls reinstall the loaded active profile without reading storage again. The runtime calls this during startup.
Parameters
Return values
Throws
Installer exceptions are converted to certificate_install_failed errors. Completion callback errors are caught and traced. Incorrect use of a supplied storage or scheduling interface may throw.
Loads saved state if needed, obtains missing or expired certificates, installs the active set and enables renewal. Call after configure().
Parameters
Return values
If stop() is called while startup is loading state, that startup cannot later enable renewal. Its callback receives nil, err with code manager_stopped. close() similarly prevents the pending startup, with code manager_closed. Pending storage and installation work is allowed to finish. A subsequent explicit start() can resume a stopped manager.
Throws
Reported storage, issuance and installation failures use the callback. Installer exceptions become certificate_install_failed errors. Completion callback errors are caught and traced. Incorrect configuration or supplied components may raise Lua errors.
Stops the automatic renewal timer while leaving explicit management methods available. This does not cancel work already in progress, but a pending startup cannot re-enable renewal after this call. Use close() for shutdown.
Parameters
Return values
Throws
Callback errors are caught and traced. Incorrect use of a supplied timer interface may throw.
Changes the active ACME directory and its account/certificate profile. Switching to the same directory updates the service settings without rebuilding certificates.
Parameters
Return values
The manager retains the previous active profile until installation and persistence succeed. If saving the active-profile selection fails after installation, it asks the installer to restore the previous set. An unsuccessful restoration is reported in err.rollback (table). The host's installer determines the effect of partial installation and empty sets.
Throws
Reported preparation, storage and installation failures use the callback. Installer exceptions become certificate_install_failed errors. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Checks or forces renewal of one managed certificate, then installs the current set.
Parameters
Return values
Throws
Reported issuance, persistence and installation failures use the callback. Installer exceptions become certificate_install_failed errors; completion callback errors are caught and traced. Incorrect options or supplied components may raise Lua errors.
Requests revocation, removes the saved record, persists the profile, and passes the remaining set to the installer. Removing the last record retains the installed certificates when using the built-in installer.
Revocation does not remove the domain from configuration. If the domain remains configured, a later startup can obtain a new certificate because its saved record is now missing. Remove the domain from the host configuration as well if the host should stop managing certificates for that name.
Parameters
Return values
Throws
Reported service, storage and installation failures use the callback. Installer exceptions become certificate_install_failed errors; completion callback errors are caught and traced. Incorrect options or supplied components may raise Lua errors.
Returns an operational snapshot without certificate private keys.
Parameters
None.
Return values
Renewal dates may be more than 49.7 days away. The manager splits long waits into timer intervals of at most 4294967295 milliseconds and checks the due dates again after each interval. An intermediate wakeup does not renew a certificate before its scheduled date.
Throws
No error for a valid manager and supported engine. Errors from a supplied engine's jobs() method propagate.
Reads managed certificate records, including private keys. Use status() for public diagnostics.
Parameters
None.
Return values
Throws
Does not throw for valid managed records.
Parameters
Return values
Throws
Does not throw for a valid domain argument and managed record.
Parameters
None.
Return values
Throws
Does not throw for a valid managed account.
Stops the renewal timer and closes the engine. Call during shutdown when using the manager directly.
Parameters
Return values
While a certificate installer is pending, returns nil, err (string), where err is "busy". The manager remains open, its timer is unchanged, and the close callback is not called. The caller must retry after installation finishes. No close retry is queued internally.
Throws
Reported engine close failures are passed to the callback. Completion callback errors are caught and traced. Incorrect use of a supplied engine or timer may throw.
domains(),certificate(), andaccount()return trusted management data that can include private keys. Do not use these values as status or logging data.
-- Certificate record returned by manager accessors
{
domain = "device.example.com",
privateKey = privateKey,
certificate = pemCertificateChain,
expiresAt = unixTime,
renewAt = unixTime,
ariCheckAt = optionalUnixTime,
ariId = optionalAriIdentifier,
explanationUrl = optionalUrl,
orderUrl = "https://acme.example/order/123",
directoryUrl = "https://acme.example/directory",
issuedAt = unixTime
}
$device label used by SharkCA.The manager uses ACME Renewal Information (ARI) when the service advertises RFC 9773 support. Otherwise, it schedules renewal from the certificate expiration time with a small random offset. Retryable renewal failures back off from 30 seconds to five minutes. A permanent failure is checked again after six hours.
A scheduled check remains busy until certificate installation completes. Installation failure is recorded in status().lastError (table), with code certificate_install_failed, and retried after six hours under the existing non-temporary error policy. The retry installs the saved certificate set; it does not request another certificate unless renewal is due. If renewal or refresh also failed, its error remains primary and lastError.install (table) contains the installation error. A successful retry clears retryAt; lastError remains the most recent recorded failure.
Dns.createClient() creates the low-level SharkTrust device client. It handles device enrollment, authenticated portal commands, DNS updates, and reverse connections. It is not an ACME client and does not persist credentials. Most applications use acme/runtime, which creates this client and the persistent DNS adapter automatically.
Resolves portal identity without making a network request.
createClient() calls this resolver automatically.
Parameters
createClient(). Defaults to an empty table.Return values
Otherwise, returns a copy of options with portalUrl (string, prefixed with https://), zoneKey (hexadecimal string), and proof (function) from the compiled identity module. It first loads etokengen, falling back to tokengen only if that load fails. If neither loads, or the selected module lacks a proof function, returns nil, err (table) with code sharktrust_not_configured. Keep the resulting identity and proof callback private.
Throws
Incorrect option types or an incompatible compiled identity module may throw. Errors raised by the selected module's info() function propagate. Missing compiled identity support is reported as nil, err.
Creates a client for one SharkTrust portal and zone. Omit the identity fields, or the entire options table, to use the compiled identity through Dns.identity(). Call it directly only when an application needs low-level SharkTrust operations or when constructing Dns.createSharkTrust() without the runtime.
local Dns = require"acme/dns"
local client, err = Dns.createClient {
portalUrl = "https://portal.example.com/sharktrust.lsp",
zoneKey = "<64-hexadecimal-character-zone-key>",
proof = hostProof, -- host callback described below; no secret option
credential = savedDeviceCredential,
http = httpOptions,
reverse = reverseOptions
}
Parameters
/sharktrust.lsp endpoint. Other paths, queries, fragments, and non-HTTPS URLs are rejected.proof(message) receives a binary-safe string and must return a 32-byte binary Hash-based Message Authentication Code (HMAC). Use a generated or hardware-backed function when the zone secret should not be exposed to Lua. It is synchronous and must not yield. There is no secret option.setCredential().ba.revcon. The client supplies the portal URL and authentication headers.The optional reverse table accepts these native reverse-connection settings. The SharkTrust client supplies url and the authentication headers:
ba.sharkclient().Return values
Throws
Proof callback errors are caught and reported as proof_failed. Incorrect option types, compiled-identity interfaces or native hashing setup can raise Lua errors.
The host supplies proof(message), a synchronous function accepting the exact binary-safe string to authenticate, including any NUL bytes. It must return a 32-byte binary HMAC-SHA-256 result and must not yield. The client constructs the message and base64url-encodes the result for X-SharkTrust-Proof. Do not change the message or encode the result in the callback. The client neither receives the zone secret nor derives its proof key.
A compiled tokengen.proof or etokengen.proof function can be supplied directly. For host-provisioned secrets, this helper recalculates the key on each call:
-- Capture globals during mako.conf evaluation for later callback calls.
local ba,string,tonumber=ba,string,tonumber
local function makeProof(zoneKey,secret)
return function(message)
local salt=zoneKey:gsub("%x%x",function(pair) return string.char(tonumber(pair,16)) end)
local key=ba.crypto.PBKDF2("sha256",secret:upper(),salt,1000,32)
return ba.crypto.hash("hmac","sha256",key)(message)(true,"binary")
end
end
makeProof(zoneKey, secret) is an illustrative host helper, not a client API. Both required arguments are strings of exactly 64 hexadecimal characters, with no defaults. It returns the callback. Assign hostProof=makeProof(zoneKey, zoneSecret), where zoneSecret is the host-provisioned secret string. Capture globals during mako.conf evaluation as shown: its loader removes the global fallback before later callback calls.
The helper uses Password-Based Key Derivation Function 2 (PBKDF2) with HMAC-SHA-256 to derive its proof key. Its password is the secret's 64 uppercase ASCII characters; its salt is the hex-decoded 32-byte zone key. It uses 1000 iterations and produces 32 bytes. Do not hex-decode the secret. The callback then authenticates the unchanged message with HMAC-SHA-256 using that derived key. Recalculating the key uses more CPU than deriving it once; this helper retains only the host-provided credentials between calls.
The host supplies its configuration and callback again on startup. The core does not persist them. Xedge's settings UI retains its own encrypted credential configuration and supplies a callback internally. Portal-issued device credentials and ACME account/certificate state still require persistence.
Use this table to find a method, then follow its link for argument types, return values, and callback behavior.
| Method | When to use it |
|---|---|
client: | Check name availability before enrollment. This does not reserve the name. |
client: | Register a device when your application owns credential persistence. The DNS adapter normally does this. |
client: | Confirm a saved registration. Runtime startup performs this check automatically. |
client: | Report an address change after startup. Runtime users should call runtime:setIpAddress(). |
client: | Publish a validation TXT record. Normally called by the DNS adapter's present() method. |
client: | Remove a validation TXT record. Normally called during DNS adapter cleanup. |
client: | Read the public IPv4 address observed by the portal. |
client: | Enable or disable portal-assisted remote access. Runtime users should call runtime:reverseConnection(). |
client: | Read reverse-connection status for a display or diagnostic check. |
client: | Read the secret device credential for private persistence. Normally used by the DNS adapter. |
client: | Restore or clear a device credential. Normally used by the DNS adapter. |
client: | Read portal identity for diagnostics or to detect saved state from another portal or zone. |
client: | Release the client during shutdown. The runtime and DNS adapter close their clients automatically. |
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
On failure returns nil, err (table). Errors include client_closed, not_enrolled, reverse_connection_unavailable and proof_failed. Except when already closed, the requested enable setting is retained even if startup fails. A later credential update attempts to restart an enabled connection.
Throws
Proof callback errors are converted to proof_failed. Incorrect native reverse-connection options or incompatible supplied components may throw.
Parameters
Return values
Setting a credential attempts to restart an enabled reverse connection. The true result confirms storage only; a returned restart error is not forwarded. Inspect reverseStatus() for connection state.
Throws
Invalid credential values are reported as nil, err. Errors raised by native options or supplied components during reverse restart may propagate.
Clears credential and proof references and closes reverse and HTTP clients.
Parameters
Return values
Throws
Completion callback errors are caught and traced. Errors from incorrect use of supplied components may propagate. Return values from underlying transport close methods are not forwarded.
Parameters
None.
Return values
Closing the client stops its reverse connection but does not reset the stored enable setting. Use connected to inspect connection state.
Throws
No error for a valid client using the supported native reverse interface. Errors raised by a custom reverse interface's status() method propagate.
Parameters
None.
Return values
Throws
Does not throw for a valid client.
Parameters
None.
Return values
Throws
Does not throw for a valid client.
client:enroll({
name = "controller",
namePolicy = "exact",
dns = "local",
info = "Xedge"
}, function(result, err) end)
exact or increment. An explicit name defaults to exact.local, wan, or both. The default is local.namePolicy="exact" requires the requested name and returns name_unavailable on a conflict. namePolicy="increment" lets the portal try numbered variants such as controller1 and controller2. If a name is supplied without a policy, the policy is exact. If no name is supplied, the portal assigns one.
The normal DNS adapter saves a random enrollment credential before contacting the portal and reuses it after failures or restarts. The updated portal recovers an existing registration by that credential before checking name availability. A different credential requesting an occupied exact name leaves the old device unchanged, triggers an immediate email attempt to the portal log recipient, and keeps the runtime retrying once per hour. Same-credential recovery does not send a conflict email. Deploy the updated portal before this client.
The dns field selects the ordinary DNS A record for the enrolled device. It does not select HTTP-01 or DNS-01.
| Value | Published address | Network effect |
|---|---|---|
local | The device's local IPv4 address, discovered automatically at startup and updated through setIpAddress() after a later network change. | Use this when local clients should connect directly to the device. This is the default. |
wan | The public source address observed by the portal. | Remote access still requires suitable router and firewall rules. |
both | Both local and public addresses. | Public DNS exposes the private address and clients may try either address. |
both is ordinary multi-address DNS. It is not split-horizon DNS and does not guarantee failover. Publishing wan does not create a NAT, port-forwarding, or firewall rule. Reverse connection is separate and routes public requests through the portal.
Application code normally does not call setAcmeRecord() or removeAcmeRecord(). The SharkTrust DNS adapter calls them from its engine-facing present() and cleanup() methods. This request format is documented for developers implementing or testing a custom DNS integration.
client:setAcmeRecord({
recordName = "_acme-challenge.controller.example.com",
recordData = "base64url-acme-validation-value",
dnsResolveTimeoutMs = 30000
}, function(result, err) end)
acme/engineacme/engine is the low-level RFC 8555 client. It communicates with an ACME directory but does not own persistent storage, renewal timers, certificate installation, Mako configuration, Xedge events, or SharkTrust enrollment. Most applications should use acme/runtime. Use the engine directly when implementing a custom manager or challenge workflow.
Creates a low-level ACME client and its serialized certificate-job queue.
local Engine = require"acme/engine"
local engine = Engine.create {
tpm = tpmInterface,
now = os.time
}
Parameters
os.time. This option is mainly useful for deterministic tests.Mako and Xedge install their platform TPM callbacks before publishing ba.tpm. Those trusted callbacks take precedence over constructor injection.
Return values
Throws
Incorrect options or dependency types may raise Lua errors. For valid options, construction has no reported operational error return.
The account argument used by certificate and revocation operations has this form:
{
email = "operator@example.com",
key = accountPrivateKey,
url = "https://acme.example/acct/123",
directoryUrl = "https://acme.example/directory"
}
The caller must persist the account returned by certificate operations. The manager does this automatically.
Downloads and validates an ACME directory to inspect provider capabilities.
Parameters
Return values
Throws
Reported transport and response errors go to the callback. A directory requiring External Account Binding returns external_account_required. Malformed JSON returns invalid_response; missing or invalid endpoint URLs return invalid_directory. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Reads the provider's Terms of Service URL before the application accepts the terms.
Parameters
Return values
Throws
Uses the same directory validation and operational error reporting as directory(). Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Queues one certificate order and immediately returns a job object. Use it when a custom manager owns account persistence, certificate persistence, installation, and renewal. Normal applications use the runtime or manager.
-- Use the callback for completion and check immediate submission errors.
local job, err = engine:certificate(service, account, {
domain = "device.example.com",
acceptTerms = true,
challenge = challengeAdapter,
key = {
type = "ecc",
curve = "SECP384R1"
},
replaces = optionalAriIdentifier,
timeout = 600,
dnsResolveTimeout = 30
}, function(result, requestErr) end)
Parameters
string email.ecc (default) or rsa. Omit this member when supplying privateKey.SECP384R1.table account, string|table privateKey, string certificate in PEM format, string orderUrl, string directoryUrl, and optional string ariId.ECC defaults to SECP384R1 and automatically uses the configured TPM interface. RSA defaults to 2048 bits and always uses a software key. New ACME account keys always use P-256.
The engine processes every authorization. An authorization already marked valid skips challenge presentation, triggering and cleanup. Pending authorizations use the selected challenge adapter as before. These low-level options do not by themselves enable SharkCA registration or IP-change replacement in the runtime or certificate manager.
Return values
Throws
Invalid submission arguments or worker setup can throw. Errors inside the certificate coroutine are caught and reported as operation_failed; reported operational failures go to the callback. String errors from native key and CSR creation become operation_failed error tables with the original message. Callback errors are caught and traced. Challenge cleanup is attempted on failure when a challenge context exists.
Reads ACME Renewal Information (ARI). The manager normally performs this check.
Parameters
Return values
Throws
Reported HTTP, certificate and response errors use the callback. Malformed JSON produces invalid_response; a missing or invalid suggested window produces invalid_renewal_info. A provider without ARI returns ari_unavailable. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Asks the ACME service to revoke a certificate. This method does not remove saved records or change the installed certificates. Normal applications use manager:revoke().
Parameters
Return values
Throws
Reported transport, signing and service failures go to the callback. A signing error string becomes a sign_failed error table; a signer's error table is preserved. No signed request is sent after signing fails. An account from a different directory returns account_directory_mismatch; missing PEM certificate data returns invalid_certificate. Callback errors are caught and traced. Incorrect arguments, invalid signing keys or supplied components may raise Lua errors.
Prepares an account key synchronously without contacting an ACME service. A custom integration can save the key before associating it with an authenticated device.
Parameters
Return values
There is no callback or automatic persistence. Save the updated account before sending its thumbprint to an enrollment service. Restoring the saved account and calling this method again reuses its key. A later certificate operation still returns the service-assigned account URL, which must also be saved.
Throws
Incorrect arguments and exceptions from supplied TPM methods propagate, as with createKey().
Creates a certificate key synchronously for a custom integration. ECC uses the configured TPM interface when available; otherwise it uses a software key. RSA always uses a software key.
Parameters
Return values
Throws
Invalid software key settings throw as described for ba.create.key(). Errors raised by the supplied TPM interface propagate. This synchronous method does not catch Lua errors or invoke a completion callback.
Lists outstanding certificate requests for diagnostics.
Parameters
None.
Return values
Throws
Does not throw for valid job state.
Cancels queued work, performs required challenge cleanup, closes owned HTTP clients, and prevents new work. Call during shutdown when using the engine directly.
Parameters
Return values
Throws
Challenge cleanup exceptions are converted to error tables. Completion callback errors are caught and traced. Incorrect use of supplied components may throw.
A challenge adapter makes an ACME validation value reachable and removes it afterward. Runtime users normally select the built-in HTTP adapter, the SharkTrust DNS adapter, or the manual DNS adapter. Implement this interface only for another DNS provider or hosting environment.
challenge.type = "dns-01" -- or "http-01" challenge:present(context, callback) challenge:cleanup(context, callback)
dns-01 or http-01.context is the engine-created table shown below. Call callback(true, nil) only when the value is ready for validation, or callback(nil, err) on failure.present(). context is the same engine-created table. Call callback(true, nil) after cleanup or callback(nil, err) on failure.For DNS-01, context has this form:
{
domain = "controller.example.com",
token = "token-from-acme-server",
keyAuthorization = "token-and-account-thumbprint",
challengeUrl = "https://acme.example/challenge/123",
recordName = "_acme-challenge.controller.example.com",
recordData = "base64url-acme-validation-value",
dnsResolveTimeoutMs = 30000
}
For HTTP-01, context has this form:
{
domain = "controller.example.com",
token = "token-from-acme-server",
challengeUrl = "https://acme.example/challenge/123",
tokenPath = "acme-challenge/token-from-acme-server",
keyAuthorization = "token-and-account-thumbprint"
}
/.well-known/ where keyAuthorization must be served.All context members are supplied by the engine. The adapter must not change them. After a successful present(), the engine calls cleanup() for success, failure, timeout, cancellation, or callback error.
engine:certificate() returns a job immediately. Use the job only to inspect or cancel a low-level certificate request. Runtime and manager users normally do not handle job objects.
Parameters
None.
Return values
Throws
Does not throw for a valid job.
Reads progress or the final outcome of a retained job object. Completion is also delivered through the certificate callback.
Parameters
None.
Return values
Throws
Does not throw for valid job state.
Cancels a queued or running operation and performs challenge cleanup when required.
Parameters
Return values
Throws
Challenge cleanup exceptions are converted to error tables. Errors from the certificate and cancellation callbacks are caught and traced.
The optional TPM interface stores ECC private keys outside Lua and performs signing or certificate-request operations with those keys. A standalone host implements these synchronous functions. Normal Mako and Xedge applications do not provide this table.
local tpmInterface = {
hasKey = function(name) end,
createKey = function(name, options) end,
jwtSign = function(name, payload, protectedHeader) end,
keyParams = function(name) end,
createCsr = function(name, distinguishedName,
certificateTypes, keyUsages) end
}
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Ignored by the ACME layer; a direct nil, err return is not recognized as a creation failure.
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
None. Installs the trusted callbacks and removes setTPM from the module, allowing only one installation.
Throws
Incorrect interface types can throw. Calling Engine.setTPM again fails because that function no longer exists. Individual platform callbacks are used and checked later by engine operations.
Certificate jobs catch Lua errors from platform callbacks and report operation_failed. Direct createKey() and standalone revocation do not provide that coroutine error handling; see their method contracts.
The ACME service and SharkTrust or SharkCA portal must present an HTTPS certificate trusted by the device. By default, the shared acme/http module uses ba.sharkclient(). If your portal uses a private CA, configure its trust store before creating the runtime or other clients.
Call require"acme/http".setCertStore(store) to set the shared default for subsequently created ACME HTTP clients.
ba.create.certstore(), or a valid binary SharkSslCAList string accepted by ba.create.sharkssl(). Pass nil to restore the default ba.sharkclient() selection. Add all CA certificates before passing a store.Returns no values. Store validation and construction follow ba.create.sharkssl(), including its Lua errors. The setting is shared across applications using this module; it does not replace HTTP clients that already exist. An explicit http.shark client option takes precedence.
Mako and Xedge log the numeric notification codes and the optional message directly. A custom host may translate them into readable messages in its own notify(code, msg) callback. Use operation callbacks for detailed errors and runtime:status() for non-secret diagnostics.
The manager stores state below acme/ by default. Each effective ACME directory has an independent profile below acme/services/, and acme/active.json selects the installed profile. A Mako SharkTrust integration stores device enrollment separately in acme/sharktrust.json.
The modules read only their current state format. They do not import the old cert/ layout, acme-v2/, legacy devkey or refresh-token state, or account and certificate files from an earlier implementation.
Account keys, certificate private keys, SharkTrust device credentials, zone secrets, and proof material are secrets. Keep the writable I/O private and exclude it from application packages, source repositories, diagnostics, and downloads.
The normal public-CA runtime requests one DNS identifier per ACME order and manages each entry in domains as a separate certificate record. It does not provide a multi-name certificate through that list.
The SharkCA profile supports a device name, an approved local IPv4 address, or both in one certificate. The low-level engine:certificate() also accepts an explicit identifiers array. The caller must supply validated identifiers and a compatible service and validation flow.
The modules do not implement:
SharkCA does not support DNS commands, reverse connections, or RSA keys. Directory changes require closing and recreating its runtime.